package transportP2P

import (
	"fmt"
	"gitee.com/jjawesomejj/awesome-util/helper/commonhelper"
	"gitee.com/jjawesomejj/awesome-util/ws"
	"github.com/gorilla/websocket"
	"github.com/net-byte/vtun/appConfig"
	"github.com/net-byte/vtun/common/config"
	"github.com/net-byte/vtun/common/netutil"
	"github.com/net-byte/vtun/common/unpacket"
	"github.com/net-byte/water"
	"log"
	"net"
)

var manager *TransportManager

var Iface *water.Interface

var bufferSize int

func getClient() ws.WebsocketClientJs {
	client := ws.WebsocketClientJs{}
	client.OnConnect(func(conn *websocket.Conn) {
		fmt.Println("连接到代理服务器")
		sid := appConfig.GetLocalSid()
		initMsg := InitMsg{
			Command: COMMAND_INIT,
			Sid:     sid,
		}
		conn.WriteJSON(initMsg)
		wsConn = conn
	})
	return client
}

var wsConn *websocket.Conn

type targetHostHandler struct {
	conn           *net.UDPConn
	messageChannel chan TransportMsg
}

func StartClient(
	iface *water.Interface,
	config config.Config,
	serverWsIp string,
	serverWsPort string,
	serverUdpPort string,
	serverWsUrl string,
	ServerHttpPort string,
	natType string,
) {
	bufferSize = config.BufferSize
	log.Println("vtun ws local client started")
	Iface = iface
	StartHttpServer(ServerHttpPort)
	client := getClient()
	client.OnMessage(func(msg string) {
		OnReadMessage(msg)
	})
	fmt.Println(serverWsUrl, "代理服务器地址")
	client.Connect(serverWsUrl)

	go tunToTLS(
		config,
		iface,
		wsConn,
		serverWsIp,
		serverWsPort,
		serverUdpPort,
		natType,
	)
}

// tunToTLS sends packets from tun to tls
func tunToTLS(
	config config.Config,
	iface *water.Interface,
	ws *websocket.Conn,
	serverWsIp string,
	serverWsPort string,
	serverUdpPort string,
	natType string,
) {
	Iface = iface
	endChan := make(chan bool, 1)
	go StartPointer(
		serverWsIp,
		serverWsPort,
		serverUdpPort,
		appConfig.GetLocalSid(),
		endChan,
		natType,
	)
	manager = &TransportManager{
		MessageConn: make(map[string]*bufferControl),
		BufferSize:  config.BufferSize,
	}
	packet := make([]byte, config.BufferSize)
	isRun := true
	go func() {
		select {
		case <-endChan:
			isRun = false
		}
	}()
	for isRun {
		n, err := iface.Read(packet)
		//fmt.Println("read")
		//fmt.Println("readMessage")
		if err != nil {
			netutil.PrintErr(err, config.Verbose)
			break
		}
		header, err := unpacket.GetPacketHeader(packet[:n])
		if err != nil {
			continue
		}
		//fmt.Println("接受到目标地址的报文:" + header.Dst.String())
		host, err := appConfig.HostConfManager.GetHost(header.Dst.String())
		//fmt.Println(header.Dst.String())
		//没有找到对应的ip地址
		if err != nil {
			continue
		}

		isFinish := appConfig.HostConfManager.CheckIsLocalRequestIp(host)
		//下面开始封包
		msg := TransportMsg{
			Command:   COMMAND_TRANSPORT,
			Payload:   packet[:n],
			TargetSid: appConfig.HostConfManager.ResolveSidByHost(host),
			IsFinish:  isFinish,
		}
		fmt.Println(msg.TargetSid, "===>")
		//fmt.Println(header.Src.String() != "172.16.0.10", "结束回环标记"+timeHelper.Now())
		//p2p 传输
		if manager.HasUdpHandler(msg.TargetSid) {
			sendToTunMsg := ClientMsgSendToTun{
				Command:  COMMAND_SEND_TO_TUN,
				Payload:  packet[:n],
				SrcSid:   appConfig.GetLocalSid(),
				IsFinish: false,
			}
			//fmt.Println("下面开始使用udp 进行发送")
			manager.PushMessage(msg.TargetSid, sendToTunMsg)
		} else {
			err = ws.WriteJSON(msg)
			if err != nil {
				fmt.Println(err, "发送数据到转发服务器失败")
				continue
			}
		}

		//err = ws.WriteJSON(msg)
		//if err != nil {
		//	fmt.Println(err, "发送数据到转发服务器失败")
		//	continue
		//}
		//fmt.Println("成功发送到转发服务器:" + timeHelper.Now())
	}
}

func OnReadMessage(msg string) {
	//下面开始解包
	sendToTunMsg := ClientMsgSendToTun{}
	//fmt.Println("接受到新的包")
	err := commonhelper.JsonDecodeWithType(msg, &sendToTunMsg)
	if err != nil {
		fmt.Println("解包失败", err)
		return
	}
	buff := sendToTunMsg.Payload
	if sendToTunMsg.IsFinish {
		fmt.Println("接受到结束回环标记")
		//结束循环 将包对应的目标地址替换为访问的ip然后发送到虚拟网卡
		ip, err := appConfig.HostConfManager.GetLocalRequestIp(sendToTunMsg.SrcSid)
		if err != nil {
			fmt.Println("无效包")
			return
		}
		//下面开始替换报文头 将响应报文头里面的来源地址替换为远程host对应的ip地址
		newPacket := buff
		newPacket = unpacket.ChangeOrigin(buff, ip)
		newPacket = unpacket.ChangeDst(newPacket, appConfig.GetLocalIp())
		_, err = Iface.Write(newPacket)
	} else {
		requestSid := sendToTunMsg.SrcSid
		ip, err := appConfig.HostConfManager.CreateRemoteRequestUserHost(requestSid)
		if err != nil {
			fmt.Println("无效包2")
			return
		}
		newPacket := buff
		newPacket = unpacket.ChangeOrigin(buff, ip)

		newPacket = unpacket.ChangeDst(newPacket, appConfig.GetLocalIp())
		_, err = Iface.Write(newPacket)
		//header, err := unpacket.GetPacketHeader(buff)
		//if err == nil {
		//	//fmt.Println(header.Dst, "dst")
		//	//fmt.Println(header.Src, "src")
		//}
	}
}
